/* 
 * File:   IndexUtil.cpp
 * Author: sriram
 * 
 * Created on 9 November, 2013, 1:08 PM
 */

#include "IndexUtil.h"
#include "../dependency/GlobalDefines.h"
#include "../dependency/debug.h"
#include <string>
IndexUtil::IndexUtil() {
}

IndexUtil::IndexUtil(const IndexUtil& orig) {
}

IndexUtil::~IndexUtil() {
}

// Returns zero if same, 1 if key1 > key2 and -1 if key1< key2
// Comparison is done only for the first noColumns
int IndexUtil::compareKeys(const char* key1, const char* key2, int noColumns, IndexHeaderPage *indexHeaderPage_){
    int status = 1;
	int numOfColumns = noColumns;
	int offset = 0;
	int intKey1 = 0, intKey2 = 0;
    float floatKey1 = 0.0, floatKey2 = 0.0, diff = 0.0;
    double doubleKey1 = 0.0, doubleKey2 = 0.0, ddiff = 0.0;
    long longKey1 = 0, longKey2 = 0;
	for (int i = 0; i < numOfColumns; ++i) {
		int colType = indexHeaderPage_->getColTypes()[i];
		switch (colType) {
		case COL_INTEGER:
			memcpy(&intKey1, &key1[offset], 4);
			memcpy(&intKey2, &key2[offset], 4);
			if (intKey1 > intKey2) {
				return 1;
			} else if (intKey1 < intKey2) {
				return -1;
			}
			break;

		case COL_FLOAT:
			memcpy(&floatKey1, &key1[offset], sizeof(float));
			memcpy(&floatKey2, &key2[offset], sizeof(float));
			DEBUG_B("k1 "<<floatKey1<<"   k2 "<<floatKey2)
			floatKey1 += 0.0;
			floatKey2 += 0.0;
			diff = floatKey1 - floatKey2;
			//			cout << endl<<diff<<endl;
			if (diff == 0.0) {
				status = 0;
			} else if (diff > 0) {
				return 1;
			} else if (diff < 0) {
				return -1;
			}
			break;
		case COL_DOUBLE:
			memcpy(&doubleKey1, &key1[offset], sizeof(double));
			memcpy(&doubleKey2, &key2[offset], sizeof(double));
			if (doubleKey1 > doubleKey2) {
				return 1;
			} else if (doubleKey1 < doubleKey2) {
				return -1;
			}
			break;
		case COL_LONG:
			memcpy(&longKey1, &key1[offset], sizeof(long));
			memcpy(&longKey2, &key2[offset], sizeof(long));
			if (longKey1 > longKey2) {
				return 1;
			} else if (longKey1 < longKey2) {
				return -1;
			}
			break;
		case COL_VARCHAR:
			if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) > 0) {
				return 1;
			} else if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) < 0) {
				return -1;
			}
			break;

		default:
			if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) > 0) {
				return 1;
			} else if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) < 0) {
				return -1;
			}
			break;

		}
		offset = offset + indexHeaderPage_->getColSizes()[i];
	}
	return 0;
}

// Returns 0 if the key1 and key 2 are equal for the given starting noColums
// Returns 1 if there is hope to search first key in key 1
// Returns 2 if there is no hope to search first key in key 1 anymore
int IndexUtil::validateKeys(const char* key1, const char* key2, vector<int> arrOperatorType, IndexHeaderPage *indexHeaderPage_){
    // Sql statmt like key1 <= key2
    int noColumns = arrOperatorType.size();
    int status = 1;
	int offset = 0;
	int intKey1 = 0, intKey2 = 0;
    float floatKey1 = 0.0, floatKey2 = 0.0, diff = 0.0;
    double doubleKey1 = 0.0, doubleKey2 = 0.0, ddiff = 0.0;
    long longKey1 = 0, longKey2 = 0;
    
	for (int i = 0; i < noColumns; ++i) {
		int colType = indexHeaderPage_->getColTypes()[i];
        int operatorType = arrOperatorType[i];
        bool isKeyValid = false;
        int cmpValue = -2; // Some invalid value
        int strcmpValue = 0; // Dummy value
		switch (colType) {
            case COL_INTEGER:
                memcpy(&intKey1, &key1[offset], 4);
                memcpy(&intKey2, &key2[offset], 4);
                
                cmpValue = (intKey1>intKey2)?1:-1;
                cmpValue = (intKey1==intKey2)?0:cmpValue;
                break;

            case COL_FLOAT:
                memcpy(&floatKey1, &key1[offset], sizeof(float));
                memcpy(&floatKey2, &key2[offset], sizeof(float));
                DEBUG_B("k1 "<<floatKey1<<"   k2 "<<floatKey2)
                floatKey1 += 0.0;
                floatKey2 += 0.0;
                diff = floatKey1 - floatKey2;
                cmpValue = (diff>0)?1:-1;
                cmpValue = (diff==0)?0:cmpValue;
                break;
            case COL_DOUBLE:
                memcpy(&doubleKey1, &key1[offset], sizeof(double));
                memcpy(&doubleKey2, &key2[offset], sizeof(double));
                cmpValue = (doubleKey1>doubleKey2)?1:-1;
                cmpValue = (doubleKey1==doubleKey2)?0:cmpValue;
                break;
            case COL_LONG:
                memcpy(&longKey1, &key1[offset], sizeof(long));
                memcpy(&longKey2, &key2[offset], sizeof(long));
                cmpValue = (longKey1>longKey2)?1:-1;
                cmpValue = (longKey1==longKey2)?0:cmpValue;
                break;
            case COL_VARCHAR:
                strcmpValue = strncmp(&key1[offset], &key2[offset],
                                    indexHeaderPage_->getColSizes()[i]);
                cmpValue = (strcmpValue>0)?1:-1;
                cmpValue = (strcmpValue==0)?0:strcmpValue;                
                break;

            default:
                strcmpValue = strncmp(&key1[offset], &key2[offset],
                                    indexHeaderPage_->getColSizes()[i]);
                cmpValue = (strcmpValue>0)?1:-1;
                cmpValue = (strcmpValue==0)?0:strcmpValue;
                break;
        }
        isKeyValid = isKeyValid || (operatorType==EQUAL_TO && cmpValue==0);
        isKeyValid = isKeyValid || (operatorType==LESS_THAN && cmpValue==-1);
        isKeyValid = isKeyValid || (operatorType==LESS_THAN_OR_EQUAL_TO && (cmpValue==-1 || cmpValue==0));
        isKeyValid = isKeyValid || (operatorType==GREATER_THAN && cmpValue==1);
        isKeyValid = isKeyValid || (operatorType==GREATER_THAN_OR_EQUAL_TO && (cmpValue==1 || cmpValue==0));        
        if(!isKeyValid){
            if(i==0)return 2; // No hope... first key itself is not satisfying to the operator type
            else return 1; // some key is not satisfying... hope to continue.
        } 
		offset = offset + indexHeaderPage_->getColSizes()[i];
	}
	return 0; // All keys have matched All keys are valid... :D
}
// Returns zero if same, 1 if key1 > key2 and -1 if key1< key2
int IndexUtil::compareKeys(const char* key1, const char* key2, IndexHeaderPage *indexHeaderPage_){
    int status = 1;
	int numOfColumns = indexHeaderPage_->getNoColumns();
	int offset = 0;
	int intKey1 = 0, intKey2 = 0;
    float floatKey1 = 0.0, floatKey2 = 0.0, diff = 0.0;
    double doubleKey1 = 0.0, doubleKey2 = 0.0, ddiff = 0.0;
    long longKey1 = 0, longKey2 = 0;
	for (int i = 0; i < numOfColumns; ++i) {
		int colType = indexHeaderPage_->getColTypes()[i];
		switch (colType) {
		case COL_INTEGER:
			memcpy(&intKey1, &key1[offset], 4);
			memcpy(&intKey2, &key2[offset], 4);
			if (intKey1 > intKey2) {
				return 1;
			} else if (intKey1 < intKey2) {
				return -1;
			}
			break;

		case COL_FLOAT:
			memcpy(&floatKey1, &key1[offset], sizeof(float));
			memcpy(&floatKey2, &key2[offset], sizeof(float));
			DEBUG_B("k1 "<<floatKey1<<"   k2 "<<floatKey2)
			floatKey1 += 0.0;
			floatKey2 += 0.0;
			diff = floatKey1 - floatKey2;
			//			cout << endl<<diff<<endl;
			if (diff == 0.0) {
				status = 0;
			} else if (diff > 0) {
				return 1;
			} else if (diff < 0) {
				return -1;
			}
			break;
		case COL_DOUBLE:
			memcpy(&doubleKey1, &key1[offset], sizeof(double));
			memcpy(&doubleKey2, &key2[offset], sizeof(double));
			if (doubleKey1 > doubleKey2) {
				return 1;
			} else if (doubleKey1 < doubleKey2) {
				return -1;
			}
			break;
		case COL_LONG:
			memcpy(&longKey1, &key1[offset], sizeof(long));
			memcpy(&longKey2, &key2[offset], sizeof(long));
			if (longKey1 > longKey2) {
				return 1;
			} else if (longKey1 < longKey2) {
				return -1;
			}
			break;
		case COL_VARCHAR:
			if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) > 0) {
				return 1;
			} else if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) < 0) {
				return -1;
			}
			break;

		default:
			if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) > 0) {
				return 1;
			} else if (strncmp(&key1[offset], &key2[offset],
					indexHeaderPage_->getColSizes()[i]) < 0) {
				return -1;
			}
			break;

		}
		offset = offset + indexHeaderPage_->getColSizes()[i];
	}
	return 0;
}

// Returns the string value of a key
string IndexUtil::keyToString(const char *key, IndexHeaderPage *indexHeaderPage_ ){
    int numOfColumns = indexHeaderPage_->getNoColumns();
	int offset = 0;
    ostringstream strStream;
	for (int i = 0; i < numOfColumns; i++) {
		int colType = indexHeaderPage_->getColTypes()[i];
		int intKey;
		float floatKey;
		double doubleKey;
		long longKey;
		char varCharKey[indexHeaderPage_->getColSizes()[i]],
				varCharKey1[indexHeaderPage_->getColSizes()[i]];
		switch (colType) {
		case COL_INTEGER:
			memcpy(&intKey, &key[offset], sizeof(int));
			strStream << intKey << ", ";
			break;
		case COL_FLOAT:
			memcpy(&floatKey, &key[offset], sizeof(float));
			strStream << floatKey << ", ";
			break;
		case COL_DOUBLE:
			memcpy(&doubleKey, &key[offset], sizeof(double));
			strStream << doubleKey << ", ";
			break;
		case COL_LONG:
			memcpy(&longKey, &key[offset], sizeof(long));
			strStream << longKey << ", ";
			break;
		case COL_VARCHAR:
			memcpy(varCharKey, &key[offset], indexHeaderPage_->getColSizes()[i]);
			strStream << varCharKey << ", ";
			break;
		default:
			memcpy(varCharKey1, &key[offset], indexHeaderPage_->getColSizes()[i]);
			strStream << varCharKey1 << ", ";
			break;
		}
		offset = offset + indexHeaderPage_->getColSizes()[i];
	}
    return strStream.str();
}